package com.acc.utils;

import apijson.JSONRequest;
import apijson.JSONResponse;
import apijson.RequestMethod;
import apijson.orm.Parser;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.acc.sys.framework.AccParser;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static apijson.JSONObject.KEY_COLUMN;
import static apijson.JSONObject.KEY_ORDER;
import static apijson.JSONRequest.*;
import static apijson.RequestMethod.GET;

@Slf4j
public class DbUtil {
    private DbUtil() {
    }

    public DbUtil(String table) {
        this.table = table;
        this.sqlJson.put(table, new JSONObject());
    }

    /**
     * 主表
     */
    private String table;
    private final JSONObject sqlJson = new JSONObject(true);

    private final Map<String, String> joinTableListName = new HashMap<>();

    /**
     * 扩展信息
     */
    private final JSONObject selectExtend = new JSONObject(true);
    private Parser<Long> parser;

    private Parser<Long> getParser() {
        if (parser == null) {
            this.parser = new AccParser();
            this.parser.setNeedVerify(false);
        }
        return this.parser;
    }

    public DbUtil setParser(Parser<Long> parser) {
        this.parser = parser;
        return this;
    }

    private JSONObject getParams(String table) {
        if (!this.table.equals(table) && !this.sqlJson.containsKey(table)) {
            this.sqlJson.put(table, new JSONObject());
        }
        return this.sqlJson.getJSONObject(table);
    }

    public static DbUtil table(String table) {
        return new DbUtil(table);
    }


    public DbUtil where(String where, Object field) {
        return this.where(where, field, this.table);
    }

    public DbUtil where(JSONObject where) {
        return this.where(where, this.table);
    }

    public DbUtil whereIn(String where, JSONArray field) {
        return this.where(where + "{}", field, this.table);
    }

    public DbUtil whereIn(String where, String field) {
        String[] array = StrUtil.split(field, ",").toArray(new String[0]);
        return this.where(where + "{}", new JSONArray(Arrays.asList(array)), this.table);
    }

    public DbUtil where(String where, Object field, String table) {
        JSONObject params = getParams(table);
        params.put(where, field);
        return this;
    }

    public DbUtil where(JSONObject where, String table) {
        JSONObject params = getParams(table);
        params.putAll(where);
        return this;
    }

    public DbUtil field(String field) {
        return this.field(field, this.table);
    }

    public DbUtil field(String field, String joinTable) {
        JSONObject params = getParams(joinTable);
        params.put(KEY_COLUMN, field);
        return this;
    }

    public DbUtil order(String field) {
        return this.where(KEY_ORDER, field, this.table);
    }

    public DbUtil info() {
        this.selectExtend.put("info@", table + apijson.JSONObject.KEY_ARRAY + "/info");
        return this;
    }

    public DbUtil total() {
        this.selectExtend.put("total@", table + apijson.JSONObject.KEY_ARRAY + "/total");
        return this;
    }

    public DbUtil selectExtendPut(String key, Object value) {
        this.selectExtend.put(key, value);
        return this;
    }

    public DbUtil selectExtendPut(JSONObject extend) {
        this.selectExtend.putAll(extend);
        return this;
    }

    /**
     * 分页
     *
     * @param page  第几页，页数从 0 开始算
     * @param count 每页数量
     * @return this
     */
    public DbUtil page(Integer page, Integer count) {
        this.sqlJson.put(KEY_QUERY, QUERY_ALL);
        this.sqlJson.put(KEY_COUNT, count);
        this.sqlJson.put(KEY_PAGE, page);
        return this;
    }


    public JSONObject findRaw() {
        return getParser().setMethod(GET).parseResponse(this.sqlJson);
    }

    public JSONObject find() {
        JSONObject data = findRaw();
        if (data.containsKey(this.table) && JSONResponse.isSuccess(data)) {
            return data.getJSONObject(this.table);
        }
        return null;
    }

    public JSONObject selectRaw(boolean isAll) {
        if (isAll) {
            this.sqlJson.put(KEY_QUERY, QUERY_ALL);
            this.sqlJson.put(KEY_COUNT, 0);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(apijson.JSONObject.KEY_ARRAY, this.sqlJson);
        jsonObject.putAll(this.selectExtend);
        return getParser().setMethod(GET).parseResponse(jsonObject);
    }

    public JSONArray select(boolean isAll) {
        JSONObject response = selectRaw(isAll);
        if (!JSONResponse.isSuccess(response)) {
            log.error("DB-select");
            log.error(response.toJSONString());
            throw new RuntimeException(response.toJSONString());
        }
        JSONArray jsonArray = response.getJSONArray(apijson.JSONObject.KEY_ARRAY);
        if (BeanUtil.isNotEmpty(jsonArray)) {
            JSONArray array = new JSONArray();
            jsonArray.forEach(obj -> {
                JSONObject item = (JSONObject) obj;
                JSONObject data = new JSONObject();
                data.putAll(item.getJSONObject(table));
                joinTableListName.forEach((joinTable, joinAlias) -> data.put(joinAlias, item.get(joinTable)));
                array.add(data);
            });
            return array;
        }
        return new JSONArray();
    }

    public DbUtil join(String joinTable, String joinFiled, String mainFiled, String joinAlias) {
        String joinParam = StrUtil.format("{}/{}/{}", KEY_ARRAY, table, mainFiled);
        JSONObject params = getParams(joinTable);
        params.put(joinFiled + "@", joinParam);
        joinTableListName.put(joinTable, joinAlias);
        return this;
    }

    public DbUtil join(String joinTable, String joinFiled, String mainFiled) {
        return join(joinTable, joinFiled, mainFiled, joinTable);
    }


    /**
     * 新增/修改
     *
     * @param params 新增修改参数
     * @param method post新增/put修改
     * @return JSONObject
     */
    public JSONObject save(JSONObject params, RequestMethod method) {
        JSONRequest request = new JSONRequest(this.table, params);
        return getParser().setMethod(method).parseResponse(request);
    }

    /**
     * 删除
     *
     * @param id id
     * @return 结果
     */
    public JSONObject delete(String id) {
        JSONObject object = new JSONObject();
        object.put("id", id);
        JSONRequest request = new JSONRequest(this.table, object);
        return getParser().setMethod(RequestMethod.DELETE).parseResponse(request);
    }


}
